<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Leaflet</title>
  <link rel="stylesheet" href="leaflet.css" />
  <script src="leaflet.js"></script>
  <!--叶片状蚂蚁路径-->
  <script src="plugins/leaflet-ant-path.js"></script>
  <!--方向插件-->
  <script src="plugins/leaflet.rotatedMarker.js"></script>
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
    }

    #map {
      height: 100vh;
    }
  </style>
</head>

<body>
  <div id="map"></div>

  <script>
    class AntPathPolyline {
      static polylineStyleConfig = [
        {
          color: "#006600",
          fillColor: "#006600",
          pulseColor: "#e5ffe5"
        },
        {
          color: "#0000cc",
          fillColor: "#0000cc",
          pulseColor: "#ccccff"
        },
        {
          color: "#e62f00",
          fillColor: "#e62f00",
          pulseColor: "#ffc2b3"
        },
        {
          color: "#8600b3",
          fillColor: "#8600b3",
          pulseColor: "#ecb3ff"
        },
        {
          color: "#b35900",
          fillColor: "#b35900",
          pulseColor: "#ffd9b3"
        },
        {
          color: "#ff9900",
          fillColor: "#ff9900",
          pulseColor: "#ffe0b3"
        },
        {
          color: "#00b2b3",
          fillColor: "#00b2b3",
          pulseColor: "#b3ffff"
        },
        {
          color: "#000000",
          fillColor: "#000000",
          pulseColor: "#FFFFFF"
        },
        {
          color: "#006699",
          fillColor: "#006699",
          pulseColor: "#b3e6ff"
        },
        {
          color: "#cc0099",
          fillColor: "#cc0099",
          pulseColor: "#ffb3ec"
        }
      ];

      static carIconConfig = [
        "./icons/car0.png",
        "./icons/car1.png",
        "./icons/car2.png",
        "./icons/car3.png",
        "./icons/car4.png",
        "./icons/car5.png",
        "./icons/car6.png",
        "./icons/car7.png",
        "./icons/car8.png",
        "./icons/car9.png"
      ];

      static positionIconConfig = "./icons/nav.svg";

      static layerGroups = {};

      // 获取当前位置方向
      static calculateBearing(lat1, lon1, lat2, lon2) {
        const dLon = (lon2 - lon1) * (Math.PI / 180);
        const y = Math.sin(dLon) * Math.cos(lat2 * (Math.PI / 180));
        const x =
          Math.cos(lat1 * (Math.PI / 180)) *
          Math.sin(lat2 * (Math.PI / 180)) -
          Math.sin(lat1 * (Math.PI / 180)) *
          Math.cos(lat2 * (Math.PI / 180)) *
          Math.cos(dLon);
        let bearing = Math.atan2(y, x) * (180 / Math.PI);

        // 将方位角规范化为0到360度之间
        if (bearing < 0) {
          bearing = (bearing + 360) % 360;
        }

        return bearing;
      }

      // 生成随机字符串
      static generateUniqueChar() {
        // 获取当前时间戳，确保每次调用都是唯一的
        const timestamp = new Date().getTime().toString(36);
        // 生成一个随机数，并转换为36进制字符串
        const randomValue = Math.random()
          .toString(36)
          .substr(2, 9);
        // 返回时间戳和随机数的组合，确保唯一性
        return timestamp + randomValue;
      }

      drawPolyline(
        map,
        points,
        width,
        polylineStyle,
        carIcon,
        layerGroupName
      ) {
        if (points.length === 0) {
          return;
        }

        if (AntPathPolyline.layerGroups[layerGroupName]) {
          map.removeLayer(AntPathPolyline.layerGroups[layerGroupName]);
          AntPathPolyline.layerGroups[layerGroupName] = L.layerGroup().addTo(
            map
          );
        } else {
          AntPathPolyline.layerGroups[layerGroupName] = L.layerGroup().addTo(
            map
          );
        }

        // 起始点
        const marker = L.marker(points[0], {
          icon: L.icon({
            iconUrl: AntPathPolyline.positionIconConfig, // 图标图片的URL
            iconSize: [32, 32], // 图标的大小
            iconAnchor: [15, 15], // 图标的锚点，即图标的位置应该放置在地图上的位置
            popupAnchor: [-3, -76] // 弹出框的锚点，即当你点击图标时，弹出框应该出现在哪个位置
          })
        }).addTo(AntPathPolyline.layerGroups[layerGroupName]);

        // 线
        L.polyline
          .antPath(points, {
            ...polylineStyle,
            opacity: 6,
            delay: 10000,
            dashArray: [5, 30]
          })
          .addTo(AntPathPolyline.layerGroups[layerGroupName]);

        // 最新的点
        L.marker(points[points.length - 1], {
          icon: L.icon({
            iconUrl: carIcon,
            iconSize: [30, 30], // icon的大小
            iconAnchor: [16, 15], // icon的渲染的位置（相对与marker）
            shadowAnchor: [0, 0], // shadow的渲染的位置（相对于marker）
            popupAnchor: [0, 0] //若是绑定了popup的popup的打开位置（相对于icon）
          }),
          title: "test",
          draggable: true,
          rotationAngle:
            points.length > 1
              ? AntPathPolyline.calculateBearing(
                points[points.length - 2][0],
                points[points.length - 2][1],
                points[points.length - 1][0],
                points[points.length - 1][1]
              )
              : 0
        }).addTo(AntPathPolyline.layerGroups[layerGroupName]);

        const circle = L.circle(points[points.length - 1], {
          stroke: true,
          dashArray: "4",
          color: "red",
          fillColor: "#f03",
          fillOpacity: 0.2,
          weight: 2,
          radius: 1200 * width
        }).addTo(AntPathPolyline.layerGroups[layerGroupName]);

        circle.on("mouseover", e => {
          alert("半径为0.5km.");
        });
      }
    }

    const map = L.map("map").setView([39.898457, 116.391844], 13);

    L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
      minZoom: 7,
      maxZoom: 16,
      attribution:
        '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);

    const points1 = [];
    const points2 = [];

    const newPoints1 = [
      [39.898457, 116.391844],
      [39.898595, 116.377947],
      [39.898341, 116.368001],
      [39.898063, 116.357144],
      [39.899095, 116.351934],
      [39.905871, 116.35067],
      [39.922329, 116.3498],
      [39.931017, 116.349671],
      [39.939104, 116.349225],
      [39.942233, 116.34991],
      [39.947263, 116.366892],
      [39.947568, 116.387537],
      [39.947764, 116.401988],
      [39.947929, 116.410824],
      [39.947558, 116.42674],
      [39.9397, 116.427338],
      [39.932404, 116.427919],
      [39.923109, 116.428377],
      [39.907094, 116.429583],
      [39.906858, 116.41404],
      [39.906622, 116.405321],
      [39.906324, 116.394954],
      [39.906308, 116.391264],
      [39.916611, 116.390748]
    ];

    const newPoints2 = JSON.parse(JSON.stringify(newPoints1)).reverse();

    const test1 = new AntPathPolyline();
    const testName1 = AntPathPolyline.generateUniqueChar();

    const test2 = new AntPathPolyline();
    const testName2 = AntPathPolyline.generateUniqueChar();

    let width = 0.25;

    let index = 0;

    const timer = setInterval(function () {
      if (index < newPoints1.length) {
        points1.push(newPoints1[index]);
        points2.push(newPoints2[index]);
        test1.drawPolyline(
          map,
          points1,
          width,
          AntPathPolyline.polylineStyleConfig[0],
          AntPathPolyline.carIconConfig[0],
          testName1
        );
        test2.drawPolyline(
          map,
          points2,
          width,
          AntPathPolyline.polylineStyleConfig[1],
          AntPathPolyline.carIconConfig[1],
          testName2
        );
        index++;
      } else {
        clearTimeout(timer);
      }
    }, 1000);

    console.log(AntPathPolyline.generateUniqueChar());

    // 叶片状蚂蚁路径效果：https://blog.csdn.net/gitblog_00009/article/details/137951724
    // 叶片状蚂蚁路径插件：https://gitcode.com/rubenspgcavalcante/leaflet-ant-path/overview?utm_source=artical_gitcode&isLogin=1
    // 使用Leaflet.rotatedMaker进行航班飞行航向模拟的实践：https://blog.csdn.net/yelangkingwuzuhu/article/details/137154712
    // 方向插件：https://gitee.com/mirrors_bbecquet/Leaflet.RotatedMarker
    // Leaflet 带箭头轨迹以及沿轨迹带方向的动态marker：https://segmentfault.com/a/1190000039319512?sort=votes
  </script>
</body>

</html>